// (win32) profiler
// $Id: profiler.cpp 156 2009-09-06 12:37:50Z Oleg.Bulychov $

#include "stdafx.h"

#if defined(_WIN32)

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#else

#include <sys/time.h> 
#include <sys/resource.h>
#include <sched.h>

#endif

#include "src/include/k_profiler.h"

using std::cout;
//__________________________________________________________________________________
static int g_Profiler_Enabled = 1;
//__________________________________________________________________________________
static int64_t g_iSubTime = 0;
static int     g_Profiler_Active = 0;
//__________________________________________________________________________________
static inline int64_t Get_Perfomance_Counter() NO_THROW_()
{
#if defined(_WIN32)
    LARGE_INTEGER n;
    ::QueryPerformanceCounter(&n);
    return n.QuadPart;
#else
    timeval tv;
    ::gettimeofday(&tv, NULL);
    return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL;
#endif
}
//__________________________________________________________________________________
static inline int64_t Get_Frequency() NO_THROW_()
{
    static int64_t g_iFrequency = 0;
    if (!g_iFrequency)
    {
#if defined(_WIN32)
        LARGE_INTEGER n;
        ::QueryPerformanceFrequency(&n);
        g_iFrequency = n.QuadPart;
#else
        g_iFrequency = 1000000LL;
#endif
    }
    return g_iFrequency;
}
//__________________________________________________________________________________
void KProfilerBase::enter() NO_THROW_()
{
    iTimeStart_ = g_iSubTime;
    iStart_ = Get_Perfomance_Counter();
}
//.............................................................................
void KProfilerBase::leave(bool bSilent, bool bForce, bool bRoot) NO_THROW_()
{
    if (!g_Profiler_Enabled)
        return;
    int64_t iFinish = Get_Perfomance_Counter();
    int64_t iSubTimeFinish = g_iSubTime;
    int64_t iTotalTime = iFinish - iStart_;
    int64_t temp = iTotalTime + iTimeStart_;
    g_iSubTime = temp;
    if(bSilent)
        return;

    int time = int((1000LL * iTotalTime) / Get_Frequency());
    if (bRoot)
    {
        cout << "total  : " << time << " ms - " << szText_ << lf
            << "subtime: " << (1000LL * iSubTimeFinish) / Get_Frequency() << " ms" << lf
            << "_________________" << lf;
    }
    else
    if(time || bForce)
    {
        cout << time << " ms - " << szText_ << lf
            << (1000LL * iSubTimeFinish) / Get_Frequency() << " ms" << lf;
    }
}
//.............................................................................
void KProfilerBase::Set_Thread_Processor(int nProcessor) NO_THROW_()
{
#if defined(_WIN32)
    ::SetThreadAffinityMask(::GetCurrentThread(), 1 << nProcessor);
#else
    cpu_set_t mask;
    CPU_ZERO(&mask);
    CPU_SET(nProcessor, &mask);
    ::sched_setaffinity(0, sizeof(mask), &mask);
    //:old version: ::sched_setaffinity(0, &mask);
 #endif
}
//__________________________________________________________________________________
void KProfilerBase::Set_Max_Priority() NO_THROW_()
{
#if !defined(DEBUG) && !defined(_DEBUG)

#if defined(_WIN32)
    ::SetPriorityClass(::GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
    ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
#else
    //:use su, #nice -n-19 ./app
    int nice = ::getpriority(PRIO_PROCESS, 0);
    if (nice >= 0)
    {
        ::setpriority(PRIO_PROCESS, 0, -19);
        int new_nice = ::getpriority(PRIO_PROCESS, 0);
        if (new_nice == nice)
            cout << "WARNING: setpriority: access denied (hint: su)" << lf;
        else
            cout << "new priority: " << new_nice << lf;
    }
#endif

#endif
}
//__________________________________________________________________________________
KProfiler::KProfiler(char const* szText, bool bSilent/* = false*/,
                     bool bForce/* = false*/) NO_THROW_():
    KProfilerBase(szText),
    silent_(bSilent),
    force_(bForce),
    enter_(g_Profiler_Active != 0)
{
    if (enter_)
        enter();
}
//.............................................................................
void KProfiler::leave() NO_THROW_()
{
    if (enter_)
    {
        KProfilerBase::leave(silent_ || !g_Profiler_Active, force_, false);
        enter_ = false;
    }
}
//__________________________________________________________________________________
void KProfilerServer::enter() NO_THROW_()
{
    if (g_Profiler_Enabled == id_)
    {
        enter_ = g_Profiler_Active == 0;
        if (enter_)
        {
            g_Profiler_Active = id_;
            g_iSubTime = 0;
            KProfilerBase::enter();
        }
    }
}
//.............................................................................
void KProfilerServer::leave(bool bSilent/* = false*/) NO_THROW_()
{
    if (enter_)
    {
        ASSERT_(id_ == g_Profiler_Active);
        KProfilerBase::leave(bSilent, true, true);
        g_Profiler_Active = 0;
        enter_ = false;
    }
}
//__________________________________________________________________________________

//EOF!
